#pragma once

#include "Logger.h"

#include <vector>
#include <cstddef>
#include <string>
#include <algorithm>

/// +-------------------+------------------+------------------+
/// | prependable bytes |  readable bytes  |  writable bytes  |
/// |                   |     (CONTENT)    |                  |
/// +-------------------+------------------+------------------+
/// |                   |                  |                  |
/// 0      <=      readerIndex   <=   writerIndex    <=     size
class Buffer
{
public:
    static const size_t kCheapPrepend = 8;   // 前8个字节用来记录数据包的长度
    static const size_t kInitialSize = 1024; // 缓冲区的初始化大小

    explicit Buffer(size_t initialSize = kInitialSize)
        : buffer_(kCheapPrepend + initialSize), readerIndex_(kCheapPrepend), writerIndex_(kCheapPrepend)
    {
    }

    // 可读数据的长度（字节）
    size_t readableBytes() const
    {
        return writerIndex_ - readerIndex_;
    }

    // buffer中可写入空间的长度（字节）
    size_t writableBytes() const
    {
        return buffer_.size() - writerIndex_;
    }

    // readerIndex_之前的空间长度。
    size_t prependableBytes() const
    {
        return readerIndex_;
    }

    // 可读数据的起始地址
    const char *peek() const
    {
        return begin() + readerIndex_;
    }

    /**
     * 读数据可能不会把数据全部读完，那么就可能readerIndex_！=kCheapPrepend
     * 即 下标[kCheapPrepend, CreaderIndex_]之间的数据已经被读了，这段空间可以被覆盖，我记为空白区
     */

    // 更新下标
    void retrieve(size_t len)
    {
        if (len < readableBytes()) // 只读取了部分数据
        {
            readerIndex_ += len;
        }
        else // len==readableBytes()  数据一次读完
        {
            retrieveAll();
        }
    }
    void retrieveAll()
    {
        readerIndex_ = writerIndex_ = kCheapPrepend;
    }

    // 将可读数据全部读出
    std::string retrieveAllAsString()
    {
        return retrieveAsString(readableBytes());
    }

    //为了调试
    std::string output();
    // 读取可读数据的前len的字节。
    std::string retrieveAsString(size_t len)
    {
        std::string result(peek(), len); // 构造
        retrieve(len);
        return result;
    }

    // 确保数据能够被容纳下
    void ensureWritableBytes(size_t len)
    {
        if (writableBytes() < len)
        {
            makeSpace(len);
        }
    }

    // 可写空间的起始地址
    char *beginWrite()
    {
        return begin() + writerIndex_;
    }
    const char *beginWrite() const
    {
        return begin() + writerIndex_;
    }

    // 往缓冲区写入
    void append(const char *data, size_t len)
    {
        ensureWritableBytes(len);
        std::copy(data, data + len, beginWrite());
        writerIndex_ += len;
    }

    // 从fd上读数据
    ssize_t readFd(int fd, int *savedErrno);
    // 通过fd发送数据
    ssize_t writeFd(int fd, int *savedErrno);

private:
    char *begin()
    {
        // buffer_.begin()是首元素的迭代器，对其解引用拿到首元素，再取地址拿到首元素地址 即数组的起始地址
        return &*buffer_.begin();
    }
    const char *begin() const
    {
        return &*buffer_.begin();
    }

    // 扩容
    void makeSpace(size_t len)
    {
        // 即空白区+writableBytes() 大于等于 len，则通过把数据往前移 把空白区利用起来
        //  if (writableBytes() + readerIndex_ >= len + kCheapPrepend)
        if (writableBytes() + prependableBytes() >= len + kCheapPrepend)
        {
            size_t readable = readableBytes();
            // 把可读数据往前移，消除空白区
            std::copy(begin() + readerIndex_,
                      begin() + writerIndex_,
                      begin() + kCheapPrepend);
            // 更新下标
            readerIndex_ = kCheapPrepend;
            // writerIndex_ = readerIndex_ + readablebBytes();  错误 ，readablebBytes() 出问题
            writerIndex_ = readerIndex_ + readable; // 这里可以用readablebBytes()
        }
        else
        {
            buffer_.resize(writerIndex_ + len);
        }
    }

    std::vector<char> buffer_;
    size_t readerIndex_; // buffer中可读数据的起始下标
    size_t writerIndex_; // buffer中可写入空间的起始下标
};